﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml;
using System.Xml.Serialization;

using urBook.Engine;

namespace urBook.Gui
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        internal AddressBook addressBook { get; set; }
        public String rootPath { get; set; }
        public String profilePath { get; set; }
        public List<ContactCard> openContacts { get; set; }
        String addressBookPath;
        GroupItem allContacts;
        Group allContactsGroup;
        GroupItem searchResultsGroup;
        Group searchResults;
        ContactCard myCard;
        bool searchActive = false;
        private Point startPoint;

        public MainWindow()
        {
            this.InitializeComponent();
            loadConfiguration();
            addressBook.refresh();
            loadData();
            openContacts = new List<ContactCard>();
        }

        internal void loadConfiguration()
        {
            rootPath = Environment.SpecialFolder.UserProfile + "\\Address Book\\";
            try
            {
                myCard = Utilities.loadContact(rootPath + "\\Configuration.config");
                profilePath = rootPath + myCard.name.formattedName;
                addressBookPath = profilePath + "\\AddressBook.book";
                addressBook = Utilities.load(addressBookPath);
            }
            catch (Exception e)
            {
                addressBook = new AddressBook();
                new ConfigurationDialog(this, true);
            }
        }

        private void GroupsList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            try
            {
                GroupItem gi = (GroupItem)GroupsList.SelectedItem;
                viewGroup(gi.group);
            }
            catch (NullReferenceException nre)
            {
                Console.WriteLine(nre.StackTrace);
            }
        }

        internal void loadData()
        {
            string oldValue = SearchValue.Text;
            SearchValue.Text = "";

            GroupsList.Items.Clear();
            allContactsGroup = new Group();
            allContactsGroup.name = "All Contacts";
            allContactsGroup.contacts = addressBook.contacts;
            allContacts = new GroupItem(this, allContactsGroup);
            allContacts.delete.Visibility = Visibility.Collapsed;
            GroupsList.Items.Add(allContacts);

            foreach (Group g in addressBook.groups)
            {
                GroupItem gi = new GroupItem(this, g);
                gi.Drop += GroupItem_Drop;
                gi.DragEnter += GroupItem_DragEnter;
                gi.AllowDrop = true;
                GroupsList.Items.Add(gi);
            }

            Group ungroupedcontacts = new Group();
            ungroupedcontacts.name = "Ungrouped";
            foreach (ContactCard c in addressBook.contacts)
                if (c.groups.Count == 0)
                    ungroupedcontacts.contacts.Add(c);
            GroupItem ungrouped = new GroupItem(this, ungroupedcontacts);
            ungrouped.delete.Visibility = Visibility.Collapsed;
            GroupsList.Items.Add(ungrouped);

            contactsList.list.Items.Clear();
            foreach (ContactCard c in addressBook.contacts)
            {
                ContactItem ci = new ContactItem(this, contactsList, c);
                ci.PreviewMouseLeftButtonDown += ContactItem_PreviewMouseLeftButtonDown;
                ci.PreviewMouseMove += ContactItem_MouseMove;
                contactsList.list.Items.Add(ci);
            }

            SearchValue.Text = oldValue;
        }

        internal void viewContact(ContactItem ci)
        {
            if (!openContacts.Contains(ci.contact))
            {
                TabItem ti = new TabItem();
                TabHeader th = new TabHeader(DetailView, ti);
                th.tabName.Content = ci.contact.name.formattedName;
                ti.Header = th;
                ContactView cv = new ContactView(this, ci.contact);
                ti.Content = cv;
                ti.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Stretch;
                DetailView.Items.Add(ti);
                DetailView.SelectedIndex = DetailView.Items.Count - 1;
                openContacts.Add(ci.contact);
            }
            else DetailView.SelectedIndex = openContacts.IndexOf(ci.contact) + 1;
        }

        internal void viewGroup(Group group)
        {
            contactsList.list.Items.Clear();
            foreach (ContactCard c in group.contacts)
            {
                ContactItem ci = new ContactItem(this, contactsList, c);
                ci.PreviewMouseLeftButtonDown += ContactItem_PreviewMouseLeftButtonDown;
                ci.PreviewMouseMove += ContactItem_MouseMove;
                contactsList.list.Items.Add(ci);
            }
            DetailView.SelectedIndex = 0;
        }

        private void UtilitiesButton_Click(object sender, RoutedEventArgs e)
        {
            UtilitiesMenu.IsOpen = !UtilitiesMenu.IsOpen;
        }

        private void SearchValue_TextChanged(object sender, TextChangedEventArgs e)
        {
            String value = SearchValue.Text.Trim().ToLower();
            if (value.Length == 0)
            {
                GroupsList.Items.Remove(searchResultsGroup);
                searchActive = false;
            }
            else if (value.Length > 1)
            {
                List<ContactCard> matchContacts = new List<ContactCard>();
                double Num;
                if (double.TryParse(value, out Num))
                    matchContacts = addressBook.contacts.FindAll(x => x.phones.Any(y => y.value.ToLower().Contains(value)));
                else if (value.Contains('@'))
                    matchContacts = addressBook.contacts.FindAll(x => x.emails.Any(y => y.value.ToLower().Contains(value)));
                else if (value.StartsWith("http://"))
                    matchContacts = addressBook.contacts.FindAll(x => x.url.ToLower().StartsWith(value));
                else
                {
                    matchContacts.AddRange(addressBook.contacts.FindAll(
                            x => x.name.formattedName.Trim().ToLower().StartsWith(value)
                        ));
                    matchContacts.AddRange(addressBook.contacts.FindAll(
                            x => x.name.formattedName.Trim().ToLower().Contains(value) &&
                                !x.name.formattedName.Trim().ToLower().StartsWith(value)
                        ));
                    matchContacts.AddRange(addressBook.contacts.FindAll(
                            x => x.company != null &&
                                 x.company.Trim().ToLower().StartsWith(value)
                        ));
                }
                searchResults = new Group() { name = "Search Results", contacts = matchContacts };
                viewGroup(searchResults);
                if (!searchActive)
                {
                    searchResultsGroup = new GroupItem(this, searchResults);
                    GroupsList.Items.Add(searchResultsGroup);
                }
                searchActive = true;
            }
        }

        private void NewContact_Click(object sender, RoutedEventArgs e)
        {
            ContactCard C = new ContactCard();
            addressBook.add(C);
            viewContact(new ContactItem(this, contactsList, C));
        }

        private void NewGroup_Click(object sender, RoutedEventArgs e)
        {
            Group G = new Group() { name = "New Group" };
            addressBook.groups.Add(G);
            GroupItem GI = new GroupItem(this, G);
            GroupsList.Items.Add(GI);
            GroupsList.SelectedIndex = GroupsList.Items.Count - 1;
            GI.GroupName.Visibility = Visibility.Collapsed;
            GI.GroupRename.Visibility = Visibility.Visible; 
        }

        private void NewProfile_Click(object sender, RoutedEventArgs e)
        {
            addressBook = new AddressBook();
            new ConfigurationDialog(this, false);
        }

        private void Save_Click(object sender, RoutedEventArgs e)
        {
            if (DetailView.SelectedIndex == 0)
            {
                String message = "Are you sure you want save all changes to your Address Book, This is operation can't be undone.";
                String caption = "Save changes to Address Book";
                MessageBoxResult result = MessageBox.Show(message, caption, MessageBoxButton.YesNo, MessageBoxImage.Question);

                if (result == MessageBoxResult.Yes)
                {
                    addressBook.refresh();
                    Utilities.save(addressBook, addressBookPath);
                }
            }
            else
            {
                ContactView selected = (ContactView)DetailView.SelectedItem;
                string[] groupsArray = selected.groups.Text.Trim().Split(new string[] { "; " }, StringSplitOptions.RemoveEmptyEntries);
                selected.contact.groups.Clear();
                foreach (string s in groupsArray)
                    selected.contact.groups.Add(s);

                selected.backup = (ContactCard)selected.contact.Clone();
                selected.Save.IsEnabled = false;

                loadData();
            }
        }

        internal void Edit_Click(object sender, RoutedEventArgs e)
        {
            foreach (ContactItem ci in contactsList.list.SelectedItems)
                viewContact(ci);
        }

        internal void Delete_Click(object sender, RoutedEventArgs e)
        {
            if (contactsList.list.SelectedItems.Count > 0)
            {
                String message = "Are you sure that you would like to delete " + (contactsList.list.SelectedItems.Count == 1 ? "this contact?" : "these contacts?");
                String caption = "Delete " + (contactsList.list.SelectedItems.Count == 1 ? "Contact" : contactsList.list.SelectedItems.Count + " contacts?");
                MessageBoxResult result = MessageBox.Show(message, caption, MessageBoxButton.YesNo, MessageBoxImage.Question);

                if (result == MessageBoxResult.Yes)
                {
                    foreach (ContactItem ci in contactsList.list.SelectedItems)
                    {
                        addressBook.contacts.Remove(ci.contact);
                        allContactsGroup.remove(ci.contact);
                        viewGroup(allContactsGroup);
                    }
                }
            }
            else if (GroupsList.SelectedItem != null && GroupsList.SelectedIndex != 0)
            {
                GroupItem gi = (GroupItem)GroupsList.SelectedItem;
                String message = "Are you sure that you would like to delete this Group?";
                String caption = "Delete " + gi.group.name;
                MessageBoxResult result = MessageBox.Show(message, caption, MessageBoxButton.YesNo, MessageBoxImage.Question);

                if (result == MessageBoxResult.Yes)
                {
                    addressBook.remove(gi.group);
                    loadData();
                }
            }
        }

        private void Refresh_Click(object sender, RoutedEventArgs e)
        {
            addressBook.refresh();
            loadData();
        }

        private void Find_Click(object sender, RoutedEventArgs e)
        {
            List<ContactCard> duplicates = Utilities.findDuplicates(addressBook);
            viewGroup(new Group() { contacts = duplicates, name = "Duplicate Contacts" });
        }

        internal void Merge_Click(object sender, RoutedEventArgs e)
        {
            List<ContactCard> selectedContacts = new List<ContactCard>();

            foreach (ContactItem ci in contactsList.list.SelectedItems)
            {
                selectedContacts.Add(ci.contact);
                addressBook.contacts.Remove(ci.contact);
                allContactsGroup.remove(ci.contact);
            }

            ContactCard C = Utilities.merge(addressBook, selectedContacts);
            addressBook.add(C);
            allContactsGroup.addToGroup(C);
            viewContact(new ContactItem(this, contactsList, C));
        }

        internal void Append_Click(object sender, RoutedEventArgs e)
        {
            List<ContactCard> items = new List<ContactCard>();
            if (contactsList.list.SelectedItems.Count > 0)
                foreach (ContactItem ci in contactsList.list.SelectedItems)
                    items.Add(ci.contact);
            else if (GroupsList.SelectedItem != null)
            {
                GroupItem gi = (GroupItem)GroupsList.SelectedItem;
                items = gi.group.contacts;
            }
            else
                items = addressBook.contacts;

            new AppendCountryCodeDialog(this, items);
        }

        private void Format_Click(object sender, RoutedEventArgs e)
        {
            Utilities.format(addressBook);
            loadData();
        }

        private void Import_Click(object sender, RoutedEventArgs e)
        {
            // Configure open file dialog box
            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
            dlg.FileName = "Contacts"; // Default file name
            dlg.DefaultExt = ".vcf"; // Default file extension
            dlg.Filter = "VCard (.vcf)|*.vcf"; // Filter files by extension

            // Show open file dialog box
            Nullable<bool> result = dlg.ShowDialog();

            // Process open file dialog box results
            if (result == true)
            {
                // Open document
                string filename = dlg.FileName;
                AddressBook import = urBook.Engine.VcfUtilities.VcfManager.import(filename);
                addressBook.contacts.AddRange(import.contacts);
                addressBook.groups.AddRange(import.groups);
                loadData();
            }
        }

        internal void Export_Click(object sender, RoutedEventArgs e)
        {
            if (contactsList.list.SelectedItems.Count > 0)
            {
                // Configure save file dialog box
                Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
                //dlg.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
                dlg.FileName = "Contacts"; // Default file name
                dlg.DefaultExt = ".vcf"; // Default file extension
                dlg.Filter = "VCard (.vcf)|*.vcf"; // Filter files by extension

                // Show save file dialog box
                Nullable<bool> result = dlg.ShowDialog();

                // Process save file dialog box results
                if (result == true)
                {
                    // Save document
                    string exportPath = dlg.FileName;

                    AddressBook exportItems = new AddressBook();
                    foreach (ContactItem ci in contactsList.list.SelectedItems)
                        exportItems.contacts.Add(ci.contact);
                    urBook.Engine.VcfUtilities.VcfManager.export(exportItems,exportPath);
                }
            }
            else if (GroupsList.SelectedItem != null)
            {
                Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
                dlg.FileName = "Contacts"; // Default file name
                dlg.DefaultExt = ".vcf"; // Default file extension
                dlg.Filter = "VCard (.vcf)|*.vcf"; // Filter files by extension

                // Show save file dialog box
                Nullable<bool> result = dlg.ShowDialog();

                // Process save file dialog box results
                if (result == true)
                {
                    // Save document
                    string exportPath = dlg.FileName;

                    AddressBook exportItems = new AddressBook();
                    GroupItem gi = (GroupItem)GroupsList.SelectedItem;
                    exportItems.contacts = gi.group.contacts;
                    urBook.Engine.VcfUtilities.VcfManager.export(exportItems, exportPath);
                }
            }
            else
            {
                Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
                dlg.FileName = "Contacts"; // Default file name
                dlg.DefaultExt = ".vcf"; // Default file extension
                dlg.Filter = "VCard (.vcf)|*.vcf"; // Filter files by extension

                // Show save file dialog box
                Nullable<bool> result = dlg.ShowDialog();

                // Process save file dialog box results
                if (result == true)
                {
                    // Save document
                    string exportPath = dlg.FileName;
                    urBook.Engine.VcfUtilities.VcfManager.export(addressBook, exportPath);
                }
            }
        }

        private void About_Click(object sender, RoutedEventArgs e)
        {
            AboutBox about = new AboutBox();
            about.Show();
        }

        private void Exit_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            String message = "Are you sure you want save all changes to your Address Book, This is operation can't be undone.";
            String caption = "Save changes to Address Book";
            MessageBoxResult result = MessageBox.Show(message, caption, MessageBoxButton.YesNoCancel, MessageBoxImage.Question);

            if (result == MessageBoxResult.Yes)
            {
                Utilities.save(addressBook, addressBookPath);
            }
            else if (result == MessageBoxResult.Cancel)
            {
                e.Cancel = true;
            }
            else
            {
                e.Cancel = false;
            }
        }

        private void ChooseProfile(object sender, MouseButtonEventArgs e)
        {
            // Configure open file dialog box
            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
            dlg.FileName = "Configuration"; // Default file name
            dlg.DefaultExt = ".config"; // Default file extension
            dlg.Filter = "Profile Configuration File (.config)|*.config"; // Filter files by extension

            // Show open file dialog box
            Nullable<bool> result = dlg.ShowDialog();

            // Process open file dialog box results
            if (result == true)
            {
                myCard = Utilities.loadContact(dlg.FileName);
                profilePath = dlg.FileName.Substring(0, dlg.FileName.LastIndexOf('\\') + 1);
                addressBookPath = profilePath + "\\AddressBook.book";
                addressBook = Utilities.load(addressBookPath);
                loadData();
            }
        }

        private void NewContact_MouseDown(object sender, MouseButtonEventArgs e)
        {
            ContactCard C = new ContactCard();
            addressBook.add(C);
            viewContact(new ContactItem(this, contactsList, C));
        }

        private void Save_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (DetailView.SelectedIndex == 0)
            {
                String message = "Are you sure you want save all changes to your Address Book, This is operation can't be undone.";
                String caption = "Save changes to Address Book";
                MessageBoxResult result = MessageBox.Show(message, caption, MessageBoxButton.YesNo, MessageBoxImage.Question);

                if (result == MessageBoxResult.Yes)
                {
                    addressBook.refresh();
                    Utilities.save(addressBook, addressBookPath);
                }
            }
            else
            {
                try
                {
                    ContactView selected = (ContactView)DetailView.SelectedItem;
                    selected.backup = (ContactCard)selected.contact.Clone();
                    selected.Save.IsEnabled = false;
                }
                catch (Exception a) { }
            }
        }

        private void Refresh_MouseDown(object sender, MouseButtonEventArgs e)
        {
            loadData();
        }

        private void MyCard_MouseDown(object sender, MouseButtonEventArgs e)
        {
            viewContact(new ContactItem(this, contactsList, myCard));
        }

        internal void AddToGroup_Click(object sender, RoutedEventArgs e) 
        {
            MenuItem item = (MenuItem)sender;
            Group group = addressBook.getGroupByName((string)item.Header);
            foreach (ContactItem ci in contactsList.list.SelectedItems)
                group.add(ci.contact);
            loadData();
        }

        internal void MoveToGroup_Click(object sender, RoutedEventArgs e)
        {
            MenuItem item = (MenuItem)sender;
            Group group = addressBook.getGroupByName((string)item.Header);
            foreach (ContactItem ci in contactsList.list.SelectedItems)
            {
                while (ci.contact.groups.Count > 0)
                    addressBook.getGroupByName(ci.contact.groups[0]).remove(ci.contact);
                group.add(ci.contact);
            }
            loadData();
        }

        private void ContactItem_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            startPoint = e.GetPosition(null);
        }

        private void ContactItem_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            Point mousePos = e.GetPosition(null);
            Vector diff = startPoint - mousePos;

            if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
            {
                ContactItem draggedContact = sender as ContactItem;
                DataObject dragData = new DataObject("Contact", draggedContact.contact);
                DragDrop.DoDragDrop(draggedContact, dragData, DragDropEffects.Move);
            }
        }

        private void GroupItem_Drop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent("Contact"))
            {
                ContactCard contact = e.Data.GetData("Contact") as ContactCard;
                GroupItem group = sender as GroupItem;
                group.group.add(contact);
                loadData();
            }
        }

        private void GroupItem_DragEnter(object sender, DragEventArgs e)
        {
            if (!e.Data.GetDataPresent("TheorderedNAme") || sender == e.Source)
            {
                e.Effects = DragDropEffects.Move;
            }
        }
    }
}